package com.cn.stepLock.chain;

import com.cn.stepLock.enums.ChainType;
import com.cn.stepLock.enums.ExecuteStatus;
import com.cn.stepLock.lambda.LambdaUtil;
import com.google.common.collect.ImmutableList;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.LockSupport;

import static com.cn.stepLock.lambda.LambdaUtil.transferDistinctList;

/**
 * @author Aaron
 * @desc
 * @createTime 2022-02-22 15:00
 * @since
 */
public class ParkProcessChain extends ProcessChain {


    public ParkProcessChain() {
        super();
        this.chainType = ChainType.PARK.getValue();
    }

    @Override
    public void run() {

        while (true){
            Task task = null;
            try {
                task = taskLinkedBlockingQueue.takeLast();
            } catch (InterruptedException e) {
                break;
            }
            task.status = ExecuteStatus.EXTCUTEING.getValue();
            bindPreQueueTaskToInvoke(task);
            processTask(task);
        }

    }

    @Override
    void offer(Task task) {
        taskLinkedBlockingQueue.offerPark(task);
    }

    private void bindPreQueueTaskToInvoke(Task task){
        Task preTask;
        while ((preTask=taskLinkedBlockingQueue.pollPark())!=null){
            task.preStepInvoeTaskList.add(preTask);
        }
    }

    protected void unParkThread(Task task) {
        LockSupport.unpark(task.ownerThread);
        unparkPresentThreadList(task,getPresentTaskList(task));
    }

    protected void unparkPresentThreadList(Task task, List<Task> presentTaskList) {
        List<Thread> unParkThreadList = transferDistinctList(presentTaskList, x -> x.ownerThread);
        unParkThreadList.remove(task.ownerThread);
        unParkThreadList.forEach(x->{
            try {
                LockSupport.unpark(x);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    protected List<Task> getPresentTaskList(Task task) {
        List<Task> preStepInvoeTaskList = task.preStepInvoeTaskList;
        Set<Task> unparkTaskSet = new HashSet<>();
        while (!preStepInvoeTaskList.isEmpty()){
            unparkTaskSet.addAll(preStepInvoeTaskList);
            preStepInvoeTaskList = LambdaUtil.mergeList(preStepInvoeTaskList, x->x.preStepInvoeTaskList);
        }
        return ImmutableList.copyOf(unparkTaskSet);
    }

}
